package com.smartandroid.sa.sherlock.internal.widget;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.util.AttributeSet;
import android.view.View;

import com.smartandroid.sa.sherlock.internal.nineoldandroids.widget.NineLinearLayout;

/**
 * A simple extension of a regular linear layout that supports the divider API
 * of Android 4.0+. The dividers are added adjacent to the children by changing
 * their layout params. If you need to rely on the margins which fall in the
 * same orientation as the layout you should wrap the child in a simple
 * {@link android.widget.FrameLayout} so it can receive the margin.
 */
public class IcsLinearLayout extends NineLinearLayout {
	private static final int[] R_styleable_LinearLayout = new int[] {
	/* 0 */android.R.attr.divider,
	/* 2 */android.R.attr.showDividers,
	/* 3 */android.R.attr.dividerPadding, };
	private static final int LinearLayout_divider = 0;
	private static final int LinearLayout_showDividers = 1;
	private static final int LinearLayout_dividerPadding = 2;

	/**
	 * Don't show any dividers.
	 */
	public static final int SHOW_DIVIDER_NONE = 0;
	/**
	 * Show a divider at the beginning of the group.
	 */
	public static final int SHOW_DIVIDER_BEGINNING = 1;
	/**
	 * Show dividers between each item in the group.
	 */
	public static final int SHOW_DIVIDER_MIDDLE = 2;
	/**
	 * Show a divider at the end of the group.
	 */
	public static final int SHOW_DIVIDER_END = 4;

	private Drawable mDivider;
	private int mDividerWidth;
	private int mDividerHeight;
	private int mShowDividers;
	private int mDividerPadding;

	public IcsLinearLayout(Context context, AttributeSet attrs) {
		super(context, attrs);

		TypedArray a = context.obtainStyledAttributes(attrs, /*
															 * com.android.internal
															 * .R.styleable.
															 */
				R_styleable_LinearLayout);

		setDividerDrawable(a
				.getDrawable(/* com.android.internal.R.styleable. */LinearLayout_divider));
		mShowDividers = a
				.getInt(/* com.android.internal.R.styleable. */LinearLayout_showDividers,
						SHOW_DIVIDER_NONE);
		mDividerPadding = a.getDimensionPixelSize(/*
												 * com.android.internal.R.styleable
												 * .
												 */LinearLayout_dividerPadding,
				0);

		a.recycle();
	}

	/**
	 * Set how dividers should be shown between items in this layout
	 * 
	 * @param showDividers
	 *            One or more of {@link #SHOW_DIVIDER_BEGINNING},
	 *            {@link #SHOW_DIVIDER_MIDDLE}, or {@link #SHOW_DIVIDER_END}, or
	 *            {@link #SHOW_DIVIDER_NONE} to show no dividers.
	 */
	public void setShowDividers(int showDividers) {
		if (showDividers != mShowDividers) {
			requestLayout();
			invalidate(); // XXX This is required if you are toggling a divider
							// off
		}
		mShowDividers = showDividers;
	}

	/**
	 * @return A flag set indicating how dividers should be shown around items.
	 * @see #setShowDividers(int)
	 */
	public int getShowDividers() {
		return mShowDividers;
	}

	/**
	 * Set a drawable to be used as a divider between items.
	 * 
	 * @param divider
	 *            Drawable that will divide each item.
	 * @see #setShowDividers(int)
	 */
	public void setDividerDrawable(Drawable divider) {
		if (divider == mDivider) {
			return;
		}

		// Fix for issue #379
		if (divider instanceof ColorDrawable
				&& Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
			divider = new IcsColorDrawable((ColorDrawable) divider);
		}

		mDivider = divider;
		if (divider != null) {
			mDividerWidth = divider.getIntrinsicWidth();
			mDividerHeight = divider.getIntrinsicHeight();
		} else {
			mDividerWidth = 0;
			mDividerHeight = 0;
		}
		setWillNotDraw(divider == null);
		requestLayout();
	}

	/**
	 * Set padding displayed on both ends of dividers.
	 * 
	 * @param padding
	 *            Padding value in pixels that will be applied to each end
	 * 
	 * @see #setShowDividers(int)
	 * @see #setDividerDrawable(Drawable)
	 * @see #getDividerPadding()
	 */
	public void setDividerPadding(int padding) {
		mDividerPadding = padding;
	}

	/**
	 * Get the padding size used to inset dividers in pixels
	 * 
	 * @see #setShowDividers(int)
	 * @see #setDividerDrawable(Drawable)
	 * @see #setDividerPadding(int)
	 */
	public int getDividerPadding() {
		return mDividerPadding;
	}

	/**
	 * Get the width of the current divider drawable.
	 * 
	 * @hide Used internally by framework.
	 */
	public int getDividerWidth() {
		return mDividerWidth;
	}

	@Override
	protected void measureChildWithMargins(View child,
			int parentWidthMeasureSpec, int widthUsed,
			int parentHeightMeasureSpec, int heightUsed) {
		final int index = indexOfChild(child);
		final int orientation = getOrientation();
		final LayoutParams params = (LayoutParams) child.getLayoutParams();
		if (hasDividerBeforeChildAt(index)) {
			if (orientation == VERTICAL) {
				// Account for the divider by pushing everything up
				params.topMargin = mDividerHeight;
			} else {
				// Account for the divider by pushing everything left
				params.leftMargin = mDividerWidth;
			}
		}

		final int count = getChildCount();
		if (index == count - 1) {
			if (hasDividerBeforeChildAt(count)) {
				if (orientation == VERTICAL) {
					params.bottomMargin = mDividerHeight;
				} else {
					params.rightMargin = mDividerWidth;
				}
			}
		}
		super.measureChildWithMargins(child, parentWidthMeasureSpec, widthUsed,
				parentHeightMeasureSpec, heightUsed);
	}

	@Override
	protected void onDraw(Canvas canvas) {
		if (mDivider != null) {
			if (getOrientation() == VERTICAL) {
				drawDividersVertical(canvas);
			} else {
				drawDividersHorizontal(canvas);
			}
		}
		super.onDraw(canvas);
	}

	void drawDividersVertical(Canvas canvas) {
		final int count = getChildCount();
		for (int i = 0; i < count; i++) {
			final View child = getChildAt(i);

			if (child != null && child.getVisibility() != GONE) {
				if (hasDividerBeforeChildAt(i)) {
					final LayoutParams lp = (LayoutParams) child
							.getLayoutParams();
					final int top = child.getTop() - lp.topMargin/*
																 * -
																 * mDividerHeight
																 */;
					drawHorizontalDivider(canvas, top);
				}
			}
		}

		if (hasDividerBeforeChildAt(count)) {
			final View child = getChildAt(count - 1);
			int bottom = 0;
			if (child == null) {
				bottom = getHeight() - getPaddingBottom() - mDividerHeight;
			} else {
				// final LayoutParams lp = (LayoutParams)
				// child.getLayoutParams();
				bottom = child.getBottom()/* + lp.bottomMargin */;
			}
			drawHorizontalDivider(canvas, bottom);
		}
	}

	void drawDividersHorizontal(Canvas canvas) {
		final int count = getChildCount();
		for (int i = 0; i < count; i++) {
			final View child = getChildAt(i);

			if (child != null && child.getVisibility() != GONE) {
				if (hasDividerBeforeChildAt(i)) {
					final LayoutParams lp = (LayoutParams) child
							.getLayoutParams();
					final int left = child.getLeft() - lp.leftMargin/*
																	 * -
																	 * mDividerWidth
																	 */;
					drawVerticalDivider(canvas, left);
				}
			}
		}

		if (hasDividerBeforeChildAt(count)) {
			final View child = getChildAt(count - 1);
			int right = 0;
			if (child == null) {
				right = getWidth() - getPaddingRight() - mDividerWidth;
			} else {
				// final LayoutParams lp = (LayoutParams)
				// child.getLayoutParams();
				right = child.getRight()/* + lp.rightMargin */;
			}
			drawVerticalDivider(canvas, right);
		}
	}

	void drawHorizontalDivider(Canvas canvas, int top) {
		mDivider.setBounds(getPaddingLeft() + mDividerPadding, top, getWidth()
				- getPaddingRight() - mDividerPadding, top + mDividerHeight);
		mDivider.draw(canvas);
	}

	void drawVerticalDivider(Canvas canvas, int left) {
		mDivider.setBounds(left, getPaddingTop() + mDividerPadding, left
				+ mDividerWidth, getHeight() - getPaddingBottom()
				- mDividerPadding);
		mDivider.draw(canvas);
	}

	/**
	 * Determines where to position dividers between children.
	 * 
	 * @param childIndex
	 *            Index of child to check for preceding divider
	 * @return true if there should be a divider before the child at childIndex
	 * @hide Pending API consideration. Currently only used internally by the
	 *       system.
	 */
	protected boolean hasDividerBeforeChildAt(int childIndex) {
		if (childIndex == 0) {
			return (mShowDividers & SHOW_DIVIDER_BEGINNING) != 0;
		} else if (childIndex == getChildCount()) {
			return (mShowDividers & SHOW_DIVIDER_END) != 0;
		} else if ((mShowDividers & SHOW_DIVIDER_MIDDLE) != 0) {
			boolean hasVisibleViewBefore = false;
			for (int i = childIndex - 1; i >= 0; i--) {
				if (getChildAt(i).getVisibility() != GONE) {
					hasVisibleViewBefore = true;
					break;
				}
			}
			return hasVisibleViewBefore;
		}
		return false;
	}
}
